#include "mesh.h"
#include <fstream>
#include <iostream>
#include <sstream>

Mesh::Mesh() : Displayable(1)
{
    glGenBuffers(1,&vertexBuffer);
    glGenBuffers(1,&colorBuffer);
    glGenBuffers(1,&indexBuffer);
    glGenBuffers(1,&pickingBuffer);
}


void Mesh::Picking()
{
    glPushMatrix();	//	On utilise PushMatrix afin que toutes les opérations sur la matrice de visualisation restent locales

    glTranslatef(translation->x(),translation->y(),translation->z());


    glRotatef(rotation->y(),0,1,0);
      glRotatef(rotation->x(),1,0,0);
    glRotatef(rotation->z(),0,0,1);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER,pickingBuffer);
    glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);

    /* activation des tableaux de sommets */

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

    /* desactivation des tableaux de sommet */

    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glPopMatrix();
}


void Mesh::RenderBuffers()
{
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER,colorBuffer);
    glColorPointer(3, GL_FLOAT, 0, 0);

    /* activation des tableaux de sommets */

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);

    /* desactivation des tableaux de sommet */

    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    glFlush();
}



void Mesh::FillBuffer()
{
    glBindBuffer(GL_ARRAY_BUFFER,vertexBuffer);

    /*!
     * 	Je définis les coordonnées des sommets de mon carré
     */

      /* float pos[12]={
                            0		,0		,0,
                            width	,0		,0,
                            width	,height	,0,
                            0		,height	,0
                        };
    */


    /*!
     * 	J'utilise la méthode glBufferData afin de remplir mon espace mémoire
     * 	premier argument : le type de buffer, deuxieme, la taille du buffer, 3 eme : les données, 4 eme ; truc à la con, voir doc
     */

    //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*12, pos, GL_STREAM_DRAW);
}


void Mesh::Display()
{

    glPushMatrix();	//	On utilise PushMatrix afin que toutes les opérations sur la matrice de visualisation restent locales

    glTranslatef(translation->x(),translation->y(),translation->z());
    glRotatef(rotation->y(),0,1,0);
      glRotatef(rotation->x(),1,0,0);

    glRotatef(rotation->z(),0,0,1);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexPointer(3, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER,colorBuffer);
    glColorPointer(3, GL_FLOAT, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER,normalBuffer);


    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_INT, 0);



    /* desactivation des tableaux de sommet */

    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_INDEX_ARRAY);

    glFlush();

glPopMatrix();

}

int Mesh::LoadMesh(std::string fileName)
{
    std::ifstream file(fileName.c_str(),std::ios::in);  /*!<    Ouverture du fichier en lecture */

    std::vector<std::string> lineContent;   /*!< Après le découpage du fichier, tout les "blocs" d'informations sont stoqué ici */
    std::string temp;

    std::vector<float>          vertices;   /*!<    Enregistre les informations concernant les sommets des mesh */
    std::vector<unsigned int>   indices;    /*!<    Enregistre les indices des faces */
    std::vector<unsigned int>   coorTextures;   /*!<    Enregistre les coordonnées des textures */
    std::vector<float>          normals;         /*!<    Enregistre les normales des sommets */
    std::vector<unsigned int> normalIndice;

    while(file>>temp)   /*!<  lit le fichier jusqu'à atteindre un délimiteur (espace, retour à la ligne)    */
    {
        lineContent.push_back(temp);
    }

    for(int i=0;i<lineContent.size();i++)   /*!<    Je parcours toutes les chaines que j'ai extraites du fichier    */
    {
        printf(" content : %s \n",lineContent[i].c_str());

        if(lineContent[i]=="vn")   /*!<    Préfixe indiquant que les prochaines informations seront les normales des   */
                {                               /*!<    sommets                                                                     */
                    for(int j=1;j<4;j++)
                    {
                        printf("VNLOL \n");
                        std::stringstream ss;
                        float f;
                        ss.str(lineContent[i+j]);
                        ss >> f;

                        normals.push_back(f);
                    }
                }


        else if( (lineContent[i])[0]=='v')   /*!<    préfixe indiquant que les 3 prochains éléments extrait sont les coordonnées */
        {                               /*!<    des sommets                                                                 */
            for(int j=1;j<4;j++)
            {
                std::stringstream ss;
                float f;
                ss.str(lineContent[i+j]);
                ss >> f;

                vertices.push_back(f);
            }
            i+=3;
        }
        else if((lineContent[i])[0]=='f')   /*!<    Préfixe indiquant que les prochaines informations seront les indices des */
        {                                   /*!<    sommets constituant la face     */

            int pos;
            if(pos=lineContent[i+1].find("/"))
            {
                for(int j=1;j<4;j++)
                {
                    std::string vertexIndice; std::string textureIndice; std::string normalIndicestr;

                    vertexIndice=lineContent[i+j].substr(0,pos);

                    if(!lineContent[i+j][pos+1]=='/')
                    {

                        textureIndice=lineContent[i+j].substr(pos,lineContent[i+j].find("/",pos));
                        normalIndicestr=lineContent[i+j].substr(lineContent[i+j].find("/",pos),temp.size());

                        std::stringstream * ss= new std::stringstream();
                        unsigned int f;
                        ss->str(vertexIndice);
                        *ss>>f;
                        indices.push_back(f);
                        ss =  new std::stringstream();
                        ss->str(textureIndice);
                        *ss>>f;
                        coorTextures.push_back(f);
                        ss =  new std::stringstream();
                        ss->str(normalIndicestr);
                        *ss>>f;
                        normalIndice.push_back(f);
                    }
                    else
                    {
                        normalIndicestr=lineContent[i+j].substr(pos+2, lineContent[i+j].size());

                        std::stringstream * ss= new std::stringstream();
                        unsigned int f;
                        ss->str(vertexIndice);
                        *ss>>f;
                        indices.push_back(f);

                        ss =  new std::stringstream();
                        ss->str(normalIndicestr);
                        *ss>>f;

                        printf(" normal Indice : %d \n",f);
                        normalIndice.push_back(f);
                    }
                }
            }
            else
            {
                for(int j=1;j<4;j++)
                {
                    std::stringstream ss;
                    unsigned int f;
                    ss.str(lineContent[i+j]);
                    ss >> f;

                    indices.push_back(f);
                }
            }
            i+=3;
        }

    }

    float fVertices[vertices.size()];
    unsigned int iIndices[indices.size()];
    float fColor[vertices.size()];
    float iNormals[normals.size()];
    float iNormalsIndices[indices.size()];

    for(int i=0;i<vertices.size();i++)
    {
        fVertices[i]=vertices.at(i);
    }

    for(int i=0;i<indices.size();i++)
    {
        iIndices[i]=indices.at(i)-1;
    }

    for(int i=0;i<vertices.size();i++)
    {
        fColor[i]=1.0;
    }

    for(int i=0;i<normals.size();i++)
    {
        iNormals[i]=normals.at(i);
        printf(" normales : %f \n",iNormals[i]);
    }

    printf(" size : %d \n",normalIndice.size());
    for (int i=0;i<normalIndice.size();i++)
    {
        iNormalsIndices[i]=normalIndice.at(i);
        printf(" normaleIndice : %d \n",normalIndice[i]);
    }

    size=indices.size();

    glBindBuffer(GL_ARRAY_BUFFER,vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vertices.size(), fVertices, GL_STREAM_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vertices.size(), fColor, GL_STREAM_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*indices.size(), iIndices, GL_STREAM_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*normals.size(), iNormals, GL_STREAM_DRAW);

    file.close();

}

void Mesh::SetPicking(unsigned char x, unsigned char y, unsigned char z)
{
    picking=1;

    unsigned char * pickColor = new unsigned char[size];

    for(int i=0;i<size;i+=3)
    {
        pickColor[i]=x;
        pickColor[i+1]=y;
        pickColor[i+2]=z;
    }

    glBindBuffer(GL_ARRAY_BUFFER,pickingBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*size, pickColor, GL_STREAM_DRAW);
}
